﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using ActivateYourGlutes.Controllers;
using ActivateYourGlutes.Model.Contracts;
using ActivateYourGlutes.Model.Providers;
using ActivateYourGlutes.Infrastructure;
using ActivateYourGlutes.Payloads.Goal;
using NUnit.Framework;
using Rhino.Mocks;

namespace ActivateYourGlutes.Tests.Unit.Controllers
{
    [TestFixture]
    public class Test_GoalController : ControllerTestBase
    {
        // Controller and dependencies
        private GoalController _controller;
        private IGoalProvider _goalProvider;
        private IBodyProvider _bodyProvider;
        
        // Demo data
        private IEnumerable<Goal> _activeGoals;
        private IEnumerable<Goal> _achievedGoals;
        private Goal _templateGoal;
        private Goal _goal;

        [SetUp]
        public override void Init()
        {
            base.Init();
            _goalProvider = MockRepository.GenerateMock<IGoalProvider>();
            _bodyProvider = MockRepository.GenerateStub<IBodyProvider>();
            _bodyProvider.Stub(bp => bp.MeasurementTypes).Return(_measurementTypes);
            _controller = new GoalController(_goalProvider, _bodyProvider);
            _controller.LocaleSettings = _localeSettings;

            _activeGoals = new List<Goal>()
             {
                 new Goal()
                     {
                         Account = null,
                         AchievedOn = null,
                         Active = true,
                         CreatedOn = new DateTime(1990, 01, 01),
                         DecreaseTo = true,
                         GoalId = 0,
                         MeasurementType = _weight,
                         TargetDate = null,
                         TargetValue = 80
                     }
             };

            _achievedGoals = new List<Goal>()
            {
               new Goal()
                   {
                       Account = null,
                       AchievedOn = new DateTime(2010, 1, 1),
                       Active = true,
                       CreatedOn = new DateTime(2009, 6, 6),
                       DecreaseTo = true,
                       GoalId = 1,
                       MeasurementType = _weight,
                       TargetDate = null,
                       TargetValue = 85
                   }
            };

            _templateGoal = new Goal()
            {
                AchievedOn = null,
                Active = false,
                CreatedOn = DateTime.Now,
                DecreaseTo = true,
                MeasurementType = _weight,
                TargetValue = 0,
                TargetDate = DateTime.Now.AddMonths(1)
            };

            _goal = new Goal()
            {
                Account = _mockAccount,
                AchievedOn = null,
                Active = false,
                CreatedOn = DateTime.Now,
                DecreaseTo = true,
                MeasurementType = _weight,
                TargetValue = 85,
                TargetDate = DateTime.Now.AddMonths(1),
                GoalId = 1
            };
        }

        [TearDown]
        public override void TearDown()
        {
            base.TearDown();
            _goalProvider = null;
            _bodyProvider = null;
            _controller = null;
            _activeGoals = null;
            _achievedGoals = null;
            _templateGoal = null;
        }

        [Test]
        public void Test_Index_Get_ReturnsView()
        {
            // Arrange
            _goalProvider.Expect(gp => gp.ActiveGoals(null)).IgnoreArguments().Return(_activeGoals);
            _goalProvider.Expect(gp => gp.RecentlyAchievedGoals(null)).IgnoreArguments().Return(_achievedGoals);

            // Act
            ViewResult result = (ViewResult) _controller.Index();

            // Assert
            var payload = (IndexPayload) result.ViewData.Model;
            Assert.AreEqual(_achievedGoals, payload.AchievedGoals);
            Assert.AreEqual(_activeGoals, payload.ActiveGoals);
            _goalProvider.VerifyAllExpectations();
        }

        [Test]
        public void Test_Create_Get_ReturnsView()
        {
            // Arrange
            _bodyProvider.Stub(bp => bp.MeasurementTypes).Return(_measurementTypes);
            _goalProvider.Expect(gp => gp.Template(null)).IgnoreArguments().Return(_templateGoal);

            // Act
            ViewResult result = (ViewResult) _controller.Create();

            // Assert
            var payload = (CreatePayload) result.ViewData.Model;
            Assert.AreEqual(_templateGoal, payload.Goal);
            Assert.AreEqual(_measurementTypes, payload.MeasurementTypes);
            Assert.AreEqual(2, payload.IncreaseDecrease.Count());
            Assert.AreEqual("Decrease to", payload.IncreaseDecrease.First().Text);
            Assert.AreEqual("Increase to", payload.IncreaseDecrease.Last().Text);
            Assert.AreEqual(true, payload.IncreaseDecrease.First().Selected);
            Assert.AreEqual(false, payload.IncreaseDecrease.Last().Selected);
            Assert.AreEqual(true.ToString(), payload.IncreaseDecrease.First().Value);
            Assert.AreEqual(false.ToString(), payload.IncreaseDecrease.Last().Value);
            _goalProvider.VerifyAllExpectations();
        }

        [Test]
        public void Test_Create_Post_RedirectsToIndex()
        {
            // Arrange
            Goal goal = new Goal() {Active = true, CreatedOn = DateTime.Now, DecreaseTo = true };
            _goalProvider.Expect(gp => gp.Add(null, null, null)).IgnoreArguments();

            // Act
            RedirectToRouteResult result = (RedirectToRouteResult) _controller.Create(goal, _weight.MeasurementTypeId, 40);
            
            // Assert
            Assert.AreEqual("Index", result.RouteValues["action"]);
            _goalProvider.VerifyAllExpectations();
        }

        [Test]
        public void Test_Detail_Get_ReturnsView()
        {
            // Arrange
            _goalProvider.Stub(gp => gp.CurrentAccount(null)).IgnoreArguments().Return(_mockAccount);
            _goalProvider.Expect(gp => gp.GetGoalById(null, 0)).IgnoreArguments().Return(_goal);

            // Act
            ViewResult result = (ViewResult) _controller.Detail(1);

            // Assert
            Assert.AreEqual(result.ViewData.Model, _goal);
            _goalProvider.VerifyAllExpectations();
        }

        // Authorization now happens in the provider layer
        /*
        [Test]
        [ExpectedException(typeof(AuthorizationException))]
        public void Test_Detail_Get_UnauthorisedAccessRaisesException()
        {
            // Arrange
            Account account = new Account();
            _goalProvider.Stub(gp => gp.CurrentAccount(null)).IgnoreArguments().Return(account);
            _goalProvider.Stub(gp => gp.GetGoalById(null, 0)).IgnoreArguments().Return(_goal);

            // Act
            ViewResult result = (ViewResult)_controller.Detail(1);

            // Assert is an expected exception as defined in the attributes
        }*/

        [Test]
        public void Test_Deactivate_Get_ReturnsView()
        {
            // Arrange
            _goalProvider.Stub(gp => gp.CurrentAccount(null)).IgnoreArguments().Return(_mockAccount);
            _goalProvider.Stub(gp => gp.GetGoalById(null, 0)).IgnoreArguments().Return(_goal);
            _goalProvider.Expect(gp => gp.Deactivate(_mockAccount, _goal));

            // Act
            RedirectToRouteResult result = (RedirectToRouteResult)_controller.Deactivate(1);

            // Assert
            Assert.AreEqual("Index", result.RouteValues["action"]);
            _goalProvider.VerifyAllExpectations();
        }

        // Authorization now happens in the model
        /*
        [Test]
        [ExpectedException(typeof(AuthorizationException))]
        public void Test_Deactivate_UnauthorisedAccessRaisesException()
        {
            // Arrange
            Account account = new Account();
            _goalProvider.Stub(gp => gp.CurrentAccount(null)).IgnoreArguments().Return(account);
            _goalProvider.Stub(gp => gp.GetGoalById(null, 0)).IgnoreArguments().Return(_goal);
            
            // Act
            RedirectToRouteResult result = (RedirectToRouteResult)_controller.Deactivate(1);

            // Assert is the expected exception attribute
        }*/
    }
}
